package org.quickserver.net.client.monitoring;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.quickserver.net.client.Host;
import org.quickserver.net.client.HostList;


















public class HostMonitoringService
{
  private static final Logger logger = Logger.getLogger(HostMonitoringService.class.getName());
  private static long monitorInterval = 1000L;
  
  private static List listToMonitor = Collections.synchronizedList(new ArrayList());
  
  private HostList hostList;
  
  private HostMonitor hostMonitor;
  private int intervalInSec;
  private List listnersList;
  private Date lastCheckedOn;
  private Date nextCheckOn;
  
  public static int getSize() { return listToMonitor.size(); }


  
  public static void add(HostList hostList, HostMonitor hostMonitor, int intervalInSec, List listnersList) {
    HostMonitoringService hms = new HostMonitoringService();
    hms.setHostList(hostList);
    hms.setHostMonitor(hostMonitor);
    hms.setIntervalInSec(intervalInSec);
    hms.setListnersList(listnersList);
    
    add(hms);
  }
  
  public static void add(HostMonitoringService hms) {
    if (listToMonitor.contains(hms)) {
      listToMonitor.remove(hms);
    }
    listToMonitor.add(hms);
  }

  
  public static boolean remove(HostMonitoringService hms) { return listToMonitor.remove(hms); }


  
  public static void clear() { listToMonitor.clear(); }


  
  public static void monitor() { monitor(false, null, null); }


  
  public static void monitor(boolean forceCheck) { monitor(forceCheck, null, null); }


  
  public static void monitor(boolean forceCheck, HostMonitoringService passedHms) { monitor(forceCheck, null, passedHms); }


  
  public static void monitor(String hostName) { monitor(false, hostName); }


  
  public static void monitor(boolean forceCheck, String hostName) { monitor(forceCheck, hostName, null); }


  
  public static void monitor(boolean forceCheck, String hostName, HostMonitoringService passedHms) {
    HostMonitoringService hms = null;
    List fullList = null;
    Host host = null;
    char newStatus = 'U';
    try {
      List list = new ArrayList(listToMonitor);
      Iterator<HostMonitoringService> iterator = list.iterator();
      
      while (iterator.hasNext()) {
        hms = iterator.next();
        
        if (passedHms != null && 
          passedHms != hms) {
          continue;
        }

        
        Date now = new Date();
        if (hms.getNextCheckOn() != null && hms.getNextCheckOn().after(now) && 
          !forceCheck) {
          continue;
        }
        fullList = hms.getHostList().getFullList();
        List<Host> activeList = new ArrayList();
        
        Iterator<Host> hostIterator = fullList.iterator();
        
        if (hostName == null) {
          hms.setLastCheckedOn(now);
          long nextTime = hms.getLastCheckedOn().getTime() + (
            hms.getIntervalInSec() / 2 * 1000);
          hms.setNextCheckOn(new Date(nextTime));
        } 
        
        while (hostIterator.hasNext()) {
          host = hostIterator.next();
          
          if (hostName != null) {
            if (!hostName.equals(host.getName())) {
              logger.log(Level.INFO, "hostName[{0}] does not match with [{1}]", 
                  new Object[] { hostName, host.getName() });
              if (host.getStatus() == 'A') {
                activeList.add(host);
              }
              continue;
            } 
            logger.log(Level.INFO, "hostName[{0}] is a match with [{1}]", 
                new Object[] { hostName, host.getName() });
          } 

          
          if (forceCheck || host.getNextCheckOn() == null || 
            host.getNextCheckOn().before(now)) {
            char oldStatus = host.getStatus();
            if (host.getStatus() != 'M') {
              try {
                newStatus = hms.getHostMonitor().monitor(host);
              } catch (Exception er) {
                logger.log(Level.WARNING, "Error in HostMonitor1: " + er, er);
                er.printStackTrace();
                newStatus = 'E';
              } 
            } else {
              newStatus = host.getStatus();
            } 
            host.setStatus(newStatus);
            
            if (newStatus == 'A') {
              activeList.add(host);
            } else if (host.getStatus() != 'M') {
              
              try {
                newStatus = hms.getHostMonitor().monitor(host);
              } catch (Exception er) {
                logger.log(Level.WARNING, "Error in HostMonitor2: " + er, er);
                er.printStackTrace();
                newStatus = 'E';
              } 
              if (newStatus == 'A') {
                activeList.add(host);
              }
              host.setStatus(newStatus);
            } 
            
            if (newStatus != oldStatus) {
              List myListnersList = hms.getListnersList();
              if (myListnersList != null) {
                Iterator<HostStateListener> listnersIterator = myListnersList.iterator();
                HostStateListener listener = null;
                while (listnersIterator.hasNext()) {
                  listener = listnersIterator.next();
                  if (listener != null) {
                    listener.stateChanged(host, oldStatus, newStatus); continue;
                  } 
                  logger.warning("listener was null!");
                } 
              } else {
                
                logger.log(Level.WARNING, 
                    "No listners set {0}; old status: {1};new status:{2}", 
                    new Object[] { host, Character.valueOf(oldStatus), Character.valueOf(newStatus) });
              } 
            } 
            if (host.getLastCheckedOn() != null) {
              long newTime = host.getLastCheckedOn().getTime() + (
                hms.getIntervalInSec() * 1000);
              host.setNextCheckOn(new Date(newTime));
            } else if (host.getStatus() != 'M') {
              logger.log(Level.WARNING, "host.getLastCheckedOn() was null {0}", host);
            
            }
          
          }
          else if (host.getStatus() == 'A') {
            activeList.add(host);
          } 


          
          now = new Date();
        } 
        hms.getHostList().setActiveList(activeList);
      } 
    } catch (Throwable e) {
      logger.log(Level.SEVERE, "Error: " + e, e);
    } 
  }
  
  static  {
    Thread t = new Thread() {
        public void run() {
          logger.fine("Started..");
          while (true) {
            try {
              HostMonitoringService.monitor();
            } catch (Throwable e) {
              logger.log(Level.SEVERE, "Bug in monitor method! " + e, e);
            } 
            try {
              Thread.sleep(monitorInterval);
            } catch (InterruptedException ex) {
              logger.log(Level.SEVERE, "Interrupted.. will return : " + ex);
              break;
            } 
          } 
        }
      };
    t.setName("HostMonitoringService-Thread");
    t.setDaemon(true);
    t.start();
  }


  
  public HostList getHostList() { return this.hostList; }


  
  public void setHostList(HostList hostList) { this.hostList = hostList; }


  
  public HostMonitor getHostMonitor() { return this.hostMonitor; }


  
  public void setHostMonitor(HostMonitor hostMonitor) { this.hostMonitor = hostMonitor; }


  
  public int getIntervalInSec() { return this.intervalInSec; }


  
  public void setIntervalInSec(int intervalInSec) { this.intervalInSec = intervalInSec; }


  
  public List getListnersList() { return this.listnersList; }


  
  public void setListnersList(List listnersList) { this.listnersList = listnersList; }

  
  public void addHostStateListner(HostStateListener listener) {
    if (this.listnersList == null) {
      this.listnersList = new ArrayList();
    }
    this.listnersList.add(listener);
  }
  
  public void removeHostStateListner(HostStateListener listener) {
    if (this.listnersList == null) {
      this.listnersList = new ArrayList();
    } else {
      this.listnersList.remove(listener);
    } 
  }

  
  public Date getLastCheckedOn() { return this.lastCheckedOn; }


  
  public void setLastCheckedOn(Date lastCheckedOn) { this.lastCheckedOn = lastCheckedOn; }


  
  public Date getNextCheckOn() { return this.nextCheckOn; }


  
  public void setNextCheckOn(Date nextCheckOn) { this.nextCheckOn = nextCheckOn; }
}
